//
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package main contains a demo of using a protobuf schema generated by ygot
// to generate a Protobuf form of the OpenConfig RIB model.
package main

import (
	"fmt"

	log "github.com/golang/glog"
	"github.com/golang/protobuf/proto"

	ocpb "github.com/openconfig/ygot/demo/protobuf_getting_started/ribproto/openconfig"
	ocepb "github.com/openconfig/ygot/demo/protobuf_getting_started/ribproto/openconfig/enums"
	ocrpb "github.com/openconfig/ygot/demo/protobuf_getting_started/ribproto/openconfig/openconfig_rib_bgp"
	ywpb "github.com/openconfig/ygot/proto/ywrapper"
)

func main() {
	rt := buildRouteProto(&ipv4Prefix{
		atomicAggregate: true,
		localPref:       100,
		med:             10,
		nextHop:         "10.0.1.1",
		origin:          ocepb.OpenconfigBgpTypesBgpOriginAttrType_OPENCONFIGBGPTYPESBGPORIGINATTRTYPE_EGP,
		originatorID:    "192.0.2.42",
		prefix:          "192.0.2.0/24",
		protocolOrigin:  ocepb.OpenconfigPolicyTypesINSTALLPROTOCOLTYPE_OPENCONFIGPOLICYTYPESINSTALLPROTOCOLTYPE_BGP,
	})

	b, err := proto.Marshal(rt)
	if err != nil {
		log.Exitf("Error marshalling proto: %v", err)
	}

	fmt.Printf("%s\n", proto.MarshalTextString(rt))
	fmt.Printf("Marshalled proto size in bytes: %d\n", len(b))
}

// ipv4Prefix describes an IPv4 Prefix within the OpenConfig BGP RIB model.
type ipv4Prefix struct {
	atomicAggregate bool                                           // atomicAggregate is set when a downstream BGP speaker has aggregated the prefix.
	localPref       uint64                                         // localPrefix is the value of the BGP LOCAL_PREFERENCE attribute.
	med             uint64                                         // med is the value of the BGP multi-exit discriminator.
	nextHop         string                                         // nextHop is the IP next-hop used for the BGP route.
	origin          ocepb.OpenconfigBgpTypesBgpOriginAttrType      // origin is the value of the ORIGIN attribute of the BGP prefix.
	originatorID    string                                         // originatorID specifies the address of the BGP originator of the prefix.
	prefix          string                                         // prefix is the IPv4 prefix for the route.
	protocolOrigin  ocepb.OpenconfigPolicyTypesINSTALLPROTOCOLTYPE // protocolOrigin specifies the route on the device via which the prefix was learnt.
}

// buildRouteProto returns a Protobuf representation a route and associated
// attribute set in the OpenConfig BGP RIB model.
func buildRouteProto(pfx *ipv4Prefix) *ocpb.Device {
	return &ocpb.Device{
		BgpRib: &ocrpb.BgpRib{
			AttrSets: &ocrpb.BgpRib_AttrSets{
				AttrSet: []*ocrpb.BgpRib_AttrSets_AttrSetKey{{
					Index: 1,
					AttrSet: &ocrpb.BgpRib_AttrSets_AttrSet{
						State: &ocrpb.BgpRib_AttrSets_AttrSet_State{
							AtomicAggregate: &ywpb.BoolValue{Value: pfx.atomicAggregate},
							Index:           &ywpb.UintValue{Value: 1},
							LocalPref:       &ywpb.UintValue{Value: pfx.localPref},
							Med:             &ywpb.UintValue{Value: pfx.med},
							NextHop:         &ywpb.StringValue{Value: pfx.nextHop},
							Origin:          pfx.origin,
							OriginatorId:    &ywpb.StringValue{Value: pfx.originatorID},
						},
					},
				}},
			},
			AfiSafis: &ocrpb.BgpRib_AfiSafis{
				AfiSafi: []*ocrpb.BgpRib_AfiSafis_AfiSafiKey{{
					AfiSafiName: ocepb.OpenconfigBgpTypesAFISAFITYPE_OPENCONFIGBGPTYPESAFISAFITYPE_IPV4_UNICAST,
					AfiSafi: &ocrpb.BgpRib_AfiSafis_AfiSafi{
						Ipv4Unicast: &ocrpb.BgpRib_AfiSafis_AfiSafi_Ipv4Unicast{
							LocRib: &ocrpb.BgpRib_AfiSafis_AfiSafi_Ipv4Unicast_LocRib{
								Routes: &ocrpb.BgpRib_AfiSafis_AfiSafi_Ipv4Unicast_LocRib_Routes{
									Route: []*ocrpb.BgpRib_AfiSafis_AfiSafi_Ipv4Unicast_LocRib_Routes_RouteKey{{
										Prefix: pfx.prefix,
										Origin: &ocrpb.BgpRib_AfiSafis_AfiSafi_Ipv4Unicast_LocRib_Routes_RouteKey_OriginOpenconfigpolicytypesinstallprotocoltype{ocepb.OpenconfigPolicyTypesINSTALLPROTOCOLTYPE_OPENCONFIGPOLICYTYPESINSTALLPROTOCOLTYPE_BGP},
										PathId: 1,
										Route: &ocrpb.BgpRib_AfiSafis_AfiSafi_Ipv4Unicast_LocRib_Routes_Route{
											State: &ocrpb.BgpRib_AfiSafis_AfiSafi_Ipv4Unicast_LocRib_Routes_Route_State{
												PathId:    &ywpb.UintValue{Value: 1},
												Prefix:    &ywpb.StringValue{Value: pfx.prefix},
												Origin:    &ocrpb.BgpRib_AfiSafis_AfiSafi_Ipv4Unicast_LocRib_Routes_Route_State_OriginOpenconfigpolicytypesinstallprotocoltype{ocepb.OpenconfigPolicyTypesINSTALLPROTOCOLTYPE_OPENCONFIGPOLICYTYPESINSTALLPROTOCOLTYPE_BGP},
												AttrIndex: &ywpb.UintValue{Value: 1},
											},
										},
									}},
								},
							},
						},
					},
				}},
			},
		},
	}
}
